<?php
/*-- Project Introduce --*/
namespace JCAT\Core\Event ;


/**
 * 事件管理器
 *
 * @author		alee
 * @access		public
 */
class EventManager
{		
	/**
	 * 声明一个事件
	 *
	 * @access	public
	 * @param 	$sEventName					string				事件名称
	 * @param 	$sNamespace='\\'			string				命名空间
	 * @param 	$sDescription=''			string				参数
	 * @param 	$arrArgvsList=array()		array				参数表
	 * @return	void
	 */
	public function DefineEvent( $sEventName, $sNamespace='\\', $sDescription='', $arrArgvsList = array() )
	{
		$this->arrHandles[$sNamespace][$sEventName] = array(
				'nHandleKeyAssigned' => 0
		) ;
		$this->arrEvents[$sNamespace][$sEventName] = array(
					'EventName' => $sEventName
					, 'Description' => $sDescription
					, 'ArgvList' => $arrArgvsList
		) ;
	}

	/**
	 * Description
	 *
	 * @access	public
	 * @param 	$sEventName								string				事件名称
	 * @param 	$sNamespace='\\'						string				命名空间
	 * @return	bool
	 */
	public function HasEventDefined($sEventName, $sNamespace='\\')
	{
		return isset($this->arrEvents[$sNamespace][$sEventName]) ;
	}
	
	/**
	 * 注册一个事件处理回调函数，返回 handle key
	 *
	 * @access	public
	 * @param 	$sEventName				string			事件名称
	 * @param 	$Callback				callback		回调函数
	 * @param 	$arrArgvs=array()		array			参数
	 * @param 	$sNamespace='\\'		string			命名空间
	 * @return	string
	 */
	public function RegisterHandle( $sEventName, $Callback, $arrArgvs = array(), $sNamespace='\\' )
	{
		if( !is_callable($Callback) )
		{
			throw new JCAT\Exception(
				JCAT\Language::SentenceEx(
					'正在将一个无效的事件相应函数(%s to %s::%s)注册到事件管理器'
					, 'JCAT', null
					, $Callback, $sNamespace, $sEventName 
				)) ;
		}
		
		$this->arrHandles[$sNamespace][$sEventName]
			[($sHandleKey=$this->arrHandles[$sNamespace][$sEventName]['nHandleKeyAssigned']++)]
			= array($Callback,$arrArgvs) ;
		
		return $sHandleKey ;
	}
	
	/**
	 * Description
	 *
	 * @access	public
	 * @param 	$sEventName				string			事件名称
	 * @param 	$Callback				callback		回调函数
	 * @param 	$sNamespace='\\'		string			命名空间
	 * @return	callback
	 */
	public function UnregisterHandle($sEventName,$sHandleKey,$sNamespace='\\')
	{
		$Handle = isset($this->arrHandles[$sNamespace][$sEventName][$sHandleKey])?
			$this->arrHandles[$sNamespace][$sEventName][$sHandleKey]: null ;
		
		unset($this->arrHandles[$sNamespace][$sEventName][$sHandleKey]) ;
		
		return $Handle ;
	}
	
	/**
	 * Description
	 *
	 * @access	public
	 * @param 	$sEventName				string			事件名称
	 * @param 	$Callback				callback		回调函数
	 * @param 	$sNamespace='\\'		string			命名空间
	 * @return	void
	 */
	public function ClearHandles($sEventName,$sNamespace='\\')
	{
		unset($this->arrHandles[$sNamespace][$sEventName]) ;
	}

	/**
	 * 查找一个事件处理函数
	 *
	 * @access	private
	 * @param	$Callback
	 * @param	$sHandle
	 * @return	string
	 */
	public function FindHandle($sEventName,$Handle,$sNamespace='\\')
	{
		if( isset($this->arrHandles[$sNamespace][$sEventName]) )
		{
			foreach ($this->arrHandles[$sNamespace][$sEventName] as $sHandleKey=>$HandleItem)
			{
				if( is_int($HandleItem) )
				{
					continue ;
				}
			
				if( is_array($Handle) )
				{
					if( is_array($HandleItem) )
					{
						if( ($Handle[0]===$HandleItem[0])
							and ( strtolower($Handle[1])===strtolower($HandleItem[1]) ) )
						{
							return $sHandleKey ;
						}
					}
				}
				
				else
				{
					if(strtolower($Handle) === strtolower($HandleItem))
					{
						return $sHandleKey ;
					}
				}
		
			}
		}
		return null ;
	}
	
	/**
	 * Description
	 *
	 * @access	public
	 * @param 	$sEventName				string			事件名称
	 * @param 	$arrInArgvs=array()		array			参数
	 * @param 	$sNamespace='\\'		string			命名空间
	 * @return	void
	 */
	public function Emit($sEventName,$arrInArgvs = array(),$sNamespace='\\')
	{
		$ReturnValue = null ;
		
		if( !isset($this->arrHandles[$sNamespace][$sEventName]) )
		{
			return $ReturnValue ;
		}
		
		foreach($this->arrHandles[$sNamespace][$sEventName] as $HandleItem) 
		{
			if( is_int($HandleItem) )
			{
				continue ;
			}
				
			list($Handle,$arrArgvs) = $HandleItem ;
			$arrArgvs = array_merge($arrInArgvs,$arrArgvs) ;
			
			try
			{
				call_user_func_array($Handle,$arrArgvs) ;
			}
			
			catch (Exception $aExcep)
			{
				switch ($aExcep->getCode())
				{
					// stop event
					case Exception::EXCEPID_STOP_EVENT :
						break(2) ;
					
					// return this handle, and set return value 
					case Exception::EXCEPID_RETURN_HANDLE :
						list($ReturnValue) = $aExcep->GetArgvs() ;
						break ;
					
					// unknow ??
					default	:
						throw $aExcep ;
						break ;
				}
			}
		}

		return $ReturnValue ;
	}
	
	/**
	 * Description
	 *
	 * @access	public
	 * @static
	 * @return	void
	 */
	static public function StopEvent()
	{
		throw new Exception(Exception::EXCEPID_STOP_EVENT) ;
	}
	
	
	/**
	 * Description
	 *
	 * @access	public
	 * @static
	 * @return	void
	 */
	static public function ReturnHandle($ReturnValue)
	{
		throw new Exception(Exception::EXCEPID_RETURN_HANDLE,array($ReturnValue)) ;
	}
	
	/**
	 * Description
	 * 
	 * @access	private
	 * @var		array
	 */
	private $arrHandles = array() ;
	
	/**
	 * Description
	 * 
	 * @access	private
	 * @var		array
	 */
	private $arrEvents = array() ;

}



?>